package com.xci.platform.auth.service;

import com.xci.platform.annotation.OperateUser;
import com.xci.platform.auth.core.AuthConstant;
import com.xci.platform.auth.core.HistoryModel;
import com.xci.platform.auth.core.HistoryOperateType;
import com.xci.platform.auth.dao.DicDao;
import com.xci.platform.auth.dao.DicDetailsDao;
import com.xci.platform.auth.entity.DicEntity;
import com.xci.platform.core.*;
import com.xci.platform.helper.CoreHelper;
import com.xci.platform.helper.StringHelper;
import com.xci.platform.helper.TreeHelper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;

/**
 * 系统字典服务
 */
@SuppressWarnings("unchecked")
@Service
public class DicService extends AuthBaseService {

    /**
     * 字典数据访问对象
     */
    @Resource
    private DicDao dicDao;

    /**
     * 字典明细数据访问对象
     */
    @Resource
    private DicDetailsDao dicDetailsDao;

    /**
     * 树形结构操作服务对象
     */
    private TreeOperateService treeOperateService;

    /**
     * 获取树形结构操作服务对象
     */
    public TreeOperateService getTreeOperateService() {
        if (treeOperateService == null) {
            treeOperateService = new TreeOperateService(dicDao);
        }
        return treeOperateService;
    }

    /**
     * 保存字典
     *
     * @param entity   字典对象
     * @param isCreate 是否新建
     */
    @Validated
    @OperateUser
    @Transactional(rollbackFor = Exception.class)
    public BoolMessage save(DicEntity entity, Boolean isCreate) {
        //添加名称简拼
        entity.setSpell(StringHelper.getSpell(entity.getName()));
        //验证父节点
        if (StringHelper.isBlank(entity.getParentId())) {
            entity.setParentId(Constant.RootNodeId);
        }
        //字典名称验证
        if (dicDao.existByCode(entity.getCode(), entity.getId()) > 0) {
            String msg = StringHelper.format("字典编码 {} 已经存在", entity.getName());
            return new BoolMessage(false, msg);
        }

        String msg;
        long startTime = CoreHelper.startWatch();
        if (isCreate) {
            entity.setPath(getTreeOperateService().buildNewPath(entity.getParentId()));//获取路径
            msg = StringHelper.format("新增字典 {}({})", entity.getName(), entity.getCode());
            dicDao.insert(entity);
            //region 历史记录
            operateHistory(buildHistory()
                    .operateType(HistoryOperateType.Insert)
                    .keyValue(entity.getId())
                    .message(msg)
                    .after(entity)
            );
            //endregion
        } else {
            msg = StringHelper.format("修改字典 {}({})", entity.getName(), entity.getCode());
            DicEntity oldEntity = queryById(entity.getId());
            dicDao.update(entity);
            //自恋名称或者编码发生变化时,更新字典明细值
            if (!oldEntity.getCode().equals(entity.getCode()) || !oldEntity.getName().equals(entity.getName())) {
                dicDetailsDao.updateDicCodeAndName(entity.getId(), entity.getCode(), entity.getName());
            }
            //region 历史记录
            operateHistory(buildHistory()
                    .operateType(HistoryOperateType.Update)
                    .keyValue(entity.getId())
                    .message(msg)
                    .before(oldEntity)
                    .after(entity)
            );
            //endregion
        }
        // 操作日志
        operateLog(AuthConstant.SystemModule.Dic, msg, CoreHelper.stopWatch(startTime));
        //更新节点叶子状态
        getTreeOperateService().updateLeafStatus();
        return BoolMessage.True;
    }

    /**
     * 删除字典
     *
     * @param id 字典主键
     */
    @Validated
    @Transactional(rollbackFor = Exception.class)
    public BoolMessage delete(@NotEmpty(message = "请指定删除的字典主键") String id) {
        DicEntity currentEntity = dicDao.queryById(id);
        if (currentEntity == null) return BoolMessage.fail("无效的字典主键");

        List<DicEntity> childs = (List<DicEntity>) TreeHelper.getChilds(dicDao.query(), id, true);
        for (DicEntity entity : childs) {
            long startTime = CoreHelper.startWatch();
            dicDao.delete(entity.getId());
            //删除字典明细
            dicDetailsDao.deleteByDicId(entity.getId());
            String msg = StringHelper.format("删除字典 {}({})", entity.getName(), entity.getCode());
            //region 历史记录
            operateHistory(buildHistory()
                    .operateType(HistoryOperateType.Delete)
                    .keyValue(entity.getId())
                    .message(msg)
                    .before(entity)
            );
            //endregion
            operateLog(AuthConstant.SystemModule.Dic, msg, CoreHelper.stopWatch(startTime)); // 操作日志
        }
        //更新节点叶子状态
        getTreeOperateService().updateLeafStatus();
        return BoolMessage.True;
    }

    /**
     * 保存拖拽数据(父节点和路径)
     *
     * @param nodeIndexs 更新的节点数据
     */
    @Transactional(rollbackFor = Exception.class)
    public BoolMessage updateNodeIndex(TreeNodeIndex[] nodeIndexs) {
        getTreeOperateService().updateParentAndPath(nodeIndexs);
        getTreeOperateService().rebuildPath(Constant.RootNodeId);
        return BoolMessage.True;
    }

    /**
     * 根据字典主键获取字典对象
     *
     * @param id 字典主键
     * @return 返回指定字典主键的字典对象
     */
    @Validated
    public DicEntity queryById(@NotNull(message = "请指定字典主键") String id) {
        return dicDao.queryById(id);
    }

    /**
     * 查询字典列表
     *
     * @return 返回符合查询条件的字典列表
     */
    public List<DicEntity> query() {
        return dicDao.query();
    }

    /**
     * 动态加载字典列表
     *
     * @param id 字典主键
     * @return 字典列表
     */
    public List<DicEntity> dynamicQuery(String id) {
        return dicDao.dynamicQuery(id);
    }

    /**
     * 获取字典名称
     *
     * @param id 字典主键
     * @return 字典名称
     */
    public String queryNameById(String id) {
        return dicDao.queryNameById(id);
    }

    /**
     * 根据字典编码获取字典对象
     *
     * @param code 字典编码
     */
    public DicEntity queryByCode(String code) {
        return dicDao.queryByCode(code);
    }

    /**
     * 根据字典编码获取字典名称
     *
     * @param code 字典编码
     */
    public String queryNameByCode(String code) {
        return dicDao.queryNameByCode(code);
    }

    /**
     * 转为节点列表
     *
     * @param modelList 模型列表
     */
    public List<TreeNode> convertToNodeList(List<DicEntity> modelList) {
        return TreeHelper.toTreeNodeList(modelList);
    }

    /**
     * 生成历史记录对象
     */
    private HistoryModel.HistoryModelBuilder buildHistory() {
        return HistoryModel.builder()
                .tableName("sys_dic")
                .tableCaption("系统字典")
                .keyName("id");
    }
}
